using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Linq.Expressions;

using EntModApp.EntServices;
using EntModApp.EntServices.Data;

namespace DemoApp.DataAccess 
{
  public partial class RoleQueryableRepository : 
    DbContextQueryableRepository<DemoAppModelDbContext, Role>,
    IQueryableRoleRepository
  {
    public RoleQueryableRepository(DemoAppModelDbContext context)
      : this(context, false)
    {
    }

    public RoleQueryableRepository()
      : this(new DemoAppModelDbContext(), true)
    {
    }

    protected RoleQueryableRepository(DemoAppModelDbContext context, bool ownContext)
      : base(context, context.Roles, ownContext)
    {
    }
  }

  public partial class RoleDataRepository : 
    DbContextDataRepository<DemoAppModelDbContext, Role, RoleLoadSettings>,
    IRoleRepository
  {
    public RoleDataRepository(DemoAppModelDbContext context)
      : this(context, false)
    {
    }

    public RoleDataRepository()
      : this(new DemoAppModelDbContext(), true)
    {
    }

    protected RoleDataRepository(DemoAppModelDbContext context, bool ownContext)
      : base(context, context.Roles, ownContext)
    {
    }

    public override IEnumerable<Role> RetrieveAll(out int total, bool retrieveTotal)
    {
      var query = new RoleLoadSettings
      {
        Paging = new PagingSettings { ComputeTotal = retrieveTotal }
      };
      return Retrieve(query, out total);
    }

    public override IEnumerable<Role> Retrieve(RoleLoadSettings query, out int total)
    {
      var dbQuery = DataSet.ApplyRoleLoadSettings(query, out total);
      return dbQuery.ToList();
    }

    public override int Count()
    {
      return DataSet.Count();
    }

    public override int Count(RoleLoadSettings query)
    {
      var dbQuery = DataSet.ApplyRoleFilterExpression(query.Filter);
      return dbQuery.Count();
    }
  }

  public static class RoleQueryableRepositoryExtensions
  {
    public static IQueryable<Role> ApplyRoleLoadSettings(this IQueryable<Role> query, RoleLoadSettings loadSettings, out int total)
    {
      if (loadSettings == null)
        loadSettings = new RoleLoadSettings();

      query = query.ApplyRoleInclusionSettings(loadSettings.Inclusion);

      query = query.ApplyRoleFilterExpression(loadSettings.Filter);

      query = query.ApplyRoleSortingSettings(loadSettings.Sorting);

      query = query.ApplyPagingSettings(loadSettings.Paging, out total);

      query = query.ApplyRoleSelectionSettings(loadSettings.Selection);

      return query;
    }

    public static IEnumerable<string> GetDirectRoleInclusionPaths(this RoleInclusionSettings inclusionSettings)
    {
      if (inclusionSettings.IncludeSecurableActions) yield return "SecurableActions";
      if (inclusionSettings.IncludeUsers) yield return "Users";

      yield break;
    }

    public static IEnumerable<string> GetRoleInclusionPaths(this RoleInclusionSettings inclusionSettings)
    {
      foreach (var path in inclusionSettings.GetDirectRoleInclusionPaths())
        yield return path;

      if (inclusionSettings.IncludeSecurableActions)
        foreach (var referencePath in inclusionSettings.IncludedSecurableActionsSettings.Inclusion.GetSecurableActionInclusionPaths())
          yield return "SecurableActions." + referencePath;
      if (inclusionSettings.IncludeUsers)
        foreach (var referencePath in inclusionSettings.IncludedUsersSettings.Inclusion.GetUserInclusionPaths())
          yield return "Users." + referencePath;

      yield break;
    }

    public static IQueryable<Role> ApplyRoleInclusionSettings(this IQueryable<Role> query, RoleInclusionSettings inclusionSettings)
    {
      foreach (var path in inclusionSettings.GetRoleInclusionPaths())
        query = query.Include(path);

      return query;
    }

    public static IQueryable<Role> ApplyRoleFilterExpression(this IQueryable<Role> query, RoleFilterExpression filterExpression)
    {
      if (filterExpression.ByKey != null)
        query = query.Where(o => o.RoleId == filterExpression.ByKey.RoleId);

      var parameter = Expression.Parameter(typeof(Role), "e");
      if (filterExpression.RoleIdFilter != null)
        query = query.Where(filterExpression.RoleIdFilter.CreateExpressionBody<Role, Guid>(RolePropertyNames.RoleId, parameter).ToLambda<Role>(parameter));
      if (filterExpression.NameFilter != null)
        query = query.Where(filterExpression.NameFilter.CreateExpressionBody<Role, string>(RolePropertyNames.Name, parameter).ToLambda<Role>(parameter));
      if (filterExpression.IsAdminFilter != null)
        query = query.Where(filterExpression.IsAdminFilter.CreateExpressionBody<Role, bool>(RolePropertyNames.IsAdmin, parameter).ToLambda<Role>(parameter));

      if (filterExpression.Skip.HasValue)
        query = query.Skip(filterExpression.Skip.Value);
      if (filterExpression.Take.HasValue)
        query = query.Take(filterExpression.Take.Value);

      return query;
    }

    public static IQueryable<Role> ApplyRoleSortingSettings(this IQueryable<Role> query, RoleSortingSettings sortingSettings)
    {
      return query;
    }

    public static IQueryable<Role> ApplyRoleSelectionSettings(this IQueryable<Role> query, RoleSelectionSettings selectionSettings)
    {
      return query;
    }

  }
}
